// PanelExtract.cpp

#include "StdAfx.h"

#include "Directory.h"

#include "../../resource.h"
#include "Common/Lang/LangUtils.h"
#include "../../ExtractCallback.h"
////////////////////////////////////////////////////////////////

#include "UpdateCallback100.h"
#include "../../App.h"
#include "../Windows.h"

#include "Common/System/Threading/Thread.h"

namespace FileManager
{
namespace FileSystem
{

using namespace Common;

class CDirectoryCopyThread: public CProgressThreadVirt
{
	HRESULT ProcessVirt();
public:
	CComPtr<IFolderOperations> FolderOperations;
	std::vector<UINT32> Indices;
	CString DestPath;
	CExtractCallbackImp* ExtractCallbackSpec;
	CComPtr<IFolderOperationsExtractCallback> ExtractCallback;
	HRESULT Result;
	bool MoveMode;

	CDirectoryCopyThread(CProgressThreadVirt::ThreadPoolType* pool):
		MoveMode(false), Result(E_FAIL), CProgressThreadVirt(pool)
	{}
};

HRESULT CDirectoryCopyThread::ProcessVirt()
{
	if (MoveMode)
	{
		Result = FolderOperations->MoveTo(&Indices.front(), Indices.size(), DestPath, ExtractCallback);
	}
	else
	{
		Result = FolderOperations->CopyTo(&Indices.front(), Indices.size(), DestPath, ExtractCallback);
	}
	return Result;
}

HRESULT CDirectory::CopyTo(const std::vector<UINT32> &indices, const CString &folder,
					   bool moveMode, bool showErrorMessages, CStringVector* messages,
					   bool &usePassword, CString &password)
{
	CComPtr<IFolderOperations> folderOperations;
	if (_folder.QueryInterface(&folderOperations) != S_OK)
	{
		CString errorMessage = Lang::LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
		if (showErrorMessages)
		{
			FileManager::CWindows::MessageBox(m_hWnd, errorMessage);
		}
		else if (messages != 0)
		{
			messages->push_back(errorMessage);
		}
		return E_FAIL;
	}

	HRESULT hRes(S_OK);
	{
		CDirectoryCopyThread extracter(&m_pool);


		extracter.ExtractCallbackSpec = new CComObject<CExtractCallbackImp>;
		extracter.ExtractCallbackSpec->FinalConstruct();
		extracter.ExtractCallback = extracter.ExtractCallbackSpec;
		extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
		extracter.ProgressDialog.CompressingMode = false;

		CString title = moveMode ?
						Lang::LangString(IDS_MOVING, 0x03020206) :
						Lang::LangString(IDS_COPYING, 0x03020205);
		CString progressWindowTitle = Lang::LangString(IDS_APP_TITLE, 0x03000000);

		extracter.ProgressDialog.MainWindow = m_hWnd; //GetParent();
		extracter.ProgressDialog.MainTitle = progressWindowTitle;
		extracter.ProgressDialog.MainAddTitle = title + _T(" ");

		extracter.ExtractCallbackSpec->OverwriteMode = Common::Archive::Extract::OverwriteMode::kAskBefore;
		extracter.ExtractCallbackSpec->Init();
		extracter.Indices.assign(indices.begin(), indices.end());
		extracter.DestPath = folder;
		extracter.FolderOperations = folderOperations;
		extracter.MoveMode = moveMode;

		extracter.ExtractCallbackSpec->PasswordIsDefined = usePassword;
		extracter.ExtractCallbackSpec->Password = password;

		hRes = extracter.Create(title, m_hWnd);
		if(S_OK != hRes)
		{
			return hRes;
		}

		if (messages != 0)
		{
			*messages = extracter.ProgressDialog.Sync.Messages;
		}
		hRes = extracter.Result;

		if (S_OK == hRes  && extracter.ExtractCallbackSpec->IsOK())
		{
			usePassword = extracter.ExtractCallbackSpec->PasswordIsDefined;
			password = extracter.ExtractCallbackSpec->Password;
		}
	}
	
	return hRes;
}


struct CThreadUpdate
{
	CComPtr<IFolderOperations> FolderOperations;
	CString FolderPrefix;
	CStringVector FileNames;
	std::vector<const wchar_t*> FileNamePointers;
	CProgressDialog2 ProgressDialog;
	CComPtr<Common::Agent::IFolderArchiveUpdateCallback> UpdateCallback;
	CUpdateCallback100Imp* UpdateCallbackSpec;
	HRESULT Result;
	System::Threading::CEvent ThreadEvent;

	CThreadUpdate ()
	{
		ThreadEvent.Create();
	}

	void Process()
	{
		try
		{
			CProgressCloser closer(ProgressDialog);
			Result = FolderOperations->CopyFrom(FolderPrefix, 
					&FileNamePointers.front(),FileNamePointers.size(), UpdateCallback);
		}
		catch(...)
		{
			Result = E_FAIL;
		}
	}
	//static THREAD_FUNC_DECL MyThreadFunction(void *param)
	static void WINAPI MyThreadFunction(LPVOID param)
	{
		((CThreadUpdate*)param)->Process();
		CThreadUpdate* pThis ((CThreadUpdate*)param);
		::SetEvent(pThis->ThreadEvent);
		pThis->Process();
		//return 0;
	}
};

HRESULT CDirectory::CopyFrom(const CString &folderPrefix, const CStringVector &filePaths,
						 bool showErrorMessages, CStringVector* messages)
{
	CComPtr<IFolderOperations> folderOperations;
	_folder.QueryInterface(&folderOperations);
	HRESULT res;
	if (!folderOperations)
	{
		res = E_NOINTERFACE;
	}
	else
	{
		CDisableTimerProcessing disableTimerProcessing(*this);
		CThreadUpdate updater;
		updater.UpdateCallbackSpec = new CComObject<CUpdateCallback100Imp>;
		updater.UpdateCallbackSpec->FinalConstruct();
		updater.UpdateCallback = updater.UpdateCallbackSpec;

		updater.UpdateCallbackSpec->ProgressDialog = &updater.ProgressDialog;

		CString title = Lang::LangString(IDS_COPYING, 0x03020205);
		CString progressWindowTitle = Lang::LangString(IDS_APP_TITLE, 0x03000000);

		updater.ProgressDialog.MainWindow = m_hWnd; //GetParent();
		updater.ProgressDialog.MainTitle = progressWindowTitle;
		updater.ProgressDialog.MainAddTitle = title + CString(_T(" "));

		updater.UpdateCallbackSpec->Init(false, _T(""));
		updater.FolderOperations = folderOperations;
		updater.FolderPrefix = folderPrefix;
		//updater.FileNames.Reserve(filePaths.Size());
		size_t i;
		for(i = 0; i < filePaths.size(); i++)
		{
			updater.FileNames.push_back(filePaths[i]);
		}
		updater.FileNamePointers.reserve(updater.FileNames.size());
		for(i = 0; i < updater.FileNames.size(); i++)
		{
			updater.FileNamePointers.push_back(updater.FileNames[i]);
		}

		m_pool->AddHighPriorityTask(CThreadUpdate::MyThreadFunction, &updater, updater.ThreadEvent);
		updater.ProgressDialog.DoModalAndWait(title, updater.ThreadEvent, m_hWnd);

		if (messages != 0)
		{
			*messages = updater.ProgressDialog.Sync.Messages;
		}

		res = updater.Result;
	}

	if (res == E_NOINTERFACE)
	{
		CString errorMessage = Lang::LangString(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
		if (showErrorMessages)
		{
			FileManager::CWindows::MessageBox(m_hWnd, errorMessage);
		}
		else if (messages != 0)
		{
			messages->push_back(errorMessage);
		}
		return E_ABORT;
	}

	return res;
}


} //namespace FileSystem
} //namespace FileManager
